package com.bodsite.rpc.thrift.client.pool;

import java.lang.reflect.Constructor;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.thrift.TServiceClient;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

import com.bodsite.common.utils.StringUtils;
import com.bodsite.rpc.spring.schema.bean.Invok;
import com.bodsite.rpc.thrift.client.ServiceDiscovery;
import com.bodsite.rpc.thrift.expetion.RpcException;
import com.bodsite.rpc.thrift.expetion.RpcException.RPC_EXPECTION;

/**
 * TServiceClient 对象池工厂类
 * @author bod
 * 2017年4月17日上午10:23:15
 */
public class ThriftClientPoolFactory implements PooledObjectFactory<TServiceClient> {
	
	private Invok invok;
	private ServiceDiscovery serviceDiscovery;
	
	public ThriftClientPoolFactory(Invok invok,ServiceDiscovery serviceDiscovery) {
		this.invok = invok;
		this.serviceDiscovery = serviceDiscovery;
	}

	/**
	 * 激活对象
	 * @author bod
	 * 2017年4月17日上午10:23:57
	 */
	@Override
	public void activateObject(PooledObject<TServiceClient> arg0) throws Exception {
		// TODO Auto-generated method stub
		
	}

	/**
	 * 销毁对象
	 * @author bod
	 * 2017年4月17日上午10:24:11
	 */
	@Override
	public void destroyObject(PooledObject<TServiceClient> serviceClientObj) throws Exception {
		TTransport transport = serviceClientObj.getObject().getInputProtocol().getTransport();
    	transport.close();		
	}

	/**
	 * 获取对象
	 * @author bod
	 * 2017年4月17日上午10:24:24
	 */
	@Override
	public PooledObject<TServiceClient> makeObject() throws Exception {
		String address = serviceDiscovery.getAddress();
		if (StringUtils.isBlank(address)) {
			throw new RpcException(RPC_EXPECTION.RPC_NOT_FOUND_SERVICE);
		}
		String[] serverAddress = address.split(":");
		String ip = serverAddress[0];
		int port = Integer.parseInt(serverAddress[1]);
		// 设置传输通道，对于非阻塞服务，需要使用TFramedTransport，它将数据分块发送
		TTransport transport = new TFramedTransport(new TSocket(ip, port, 3000),1024*1024*2);
		TProtocol protocol = new TCompactProtocol(transport);
		Constructor<TServiceClient> con = (Constructor<TServiceClient>) invok.getClient()
				.getConstructor(TProtocol.class);
		TServiceClient clinet = (TServiceClient) con.newInstance(protocol);
        transport.open();
        return new DefaultPooledObject<TServiceClient>(clinet);
	}

	public GenericObjectPool<TServiceClient> getTServiceClientPool(){
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setMaxTotal(32);
		poolConfig.setMaxIdle(10);
		poolConfig.setMinIdle(5);	
		//指明若在对象池空时调用borrowObject方法的行为被设定成等待，最多等待多少毫秒。如果等待时间超过了这个数值，则会抛出一个java.util.NoSuchElementException异常。如果这个值不是正数，表示无限期等待
		poolConfig.setMaxWaitMillis(2000);
		//设定在进行后台对象清理时，视休眠时间超过了多少毫秒的对象为过期。过期的对象将被回收。如果这个值不是正数，那么对休眠时间没有特别的约束
		poolConfig.setMinEvictableIdleTimeMillis(180000);
		//设定间隔每过多少毫秒进行一次后台对象清理的行动。如果这个值不是正数，则实际上不会进行后台对象清理
		poolConfig.setTimeBetweenEvictionRunsMillis(180000/ 2L);
//				poolConfig.testOnBorrow = true;
		return new GenericObjectPool<TServiceClient>(this, poolConfig);
	}
	
	/**
	 * 钝化对象
	 * @author bod
	 * 2017年4月17日上午10:24:57
	 */
	@Override
	public void passivateObject(PooledObject<TServiceClient> arg0) throws Exception {
		
	}

	/**
	 * 验证对象
	 * @author bod
	 * 2017年4月17日上午10:25:15
	 */
	@Override
	public boolean validateObject(PooledObject<TServiceClient> serviceClientObj) {
		if (serviceClientObj == null || serviceClientObj.getObject() == null){
    		return false;
    	}
    	TTransport transport = serviceClientObj.getObject().getInputProtocol().getTransport();
    	return transport.isOpen();
	}

}
